1. Problem
You need to define business
rules using facts that an orchestration cannot provide. The facts may
not be available in the orchestration, or you may need to reuse a fact
across many instances of the orchestration.
2. Solution
A business rule
performs actions when conditions defined in the Business Rule Composer
are true. For example, an action may modify a value in a message. The
BizTalk developer creates a condition from facts, which are pieces of
information the rules engine can examine. Most often, the rules engine
will examine facts from the messages BizTalk directly processes. The
orchestration invoking the rules engine directly provides these facts.
However, sometimes a rule needs to be based on facts that are not
available in the orchestration. The rules engine can retrieve these
external facts with a custom fact retriever.
In this example, a
business rule will schedule a customer's service request only if the
customer's address is in the Northwind database. The customer's address
may be different each time the orchestration invokes the rules engine.
The customer's address is called a short-term fact
because the orchestration provides the fact every time it invokes the
rules engine. However, instead of opening a new connection to the
database each time the orchestration invokes the rules engine, this
example reuses the same connection to the Northwind database over and
over again. Reusing the database connection makes it a long-term fact. The BizTalk developer must provide long-term facts to the rules engine with the IFactRetriever
interface. The custom fact retriever created in this recipe provides
the connection to the Northwind database to the rules engine.
NOTE
The Northwind database is a sample database that can be downloaded from Microsoft's site.
Use the following steps to create the custom fact retriever:
Open Visual Studio, and create a new class library project.
Add a reference to the Microsoft.RuleEngine.dll assembly. This assembly is located in the root of the BizTalk installation directory. This may be in either $\Program Files\Common Files\Microsoft BizTalk or $\Program Files\Microsoft BizTalk Server 2010\.
Implement the Microsoft.RuleEngine.IFactRetriever interface. This interface defines one method called UpdateFacts.
Within the UpdateFacts method, add code to check whether the factsHandleIn parameter is null. If the factsHandleIn parameter is null, create and return an instance of the Microsoft.RuleEngine.DataConnection class. If the factsHandleIn parameter is not null, simply return it from the method. When completed, the code should appear as in Listing 1.
Example 1. Completed Custom Fact Retriever
using System.Data.SqlClient; using Microsoft.RuleEngine;
namespace CustomFactRetriever { public class AssertDBConnection : IFactRetriever { public object UpdateFacts(RuleSetInfo ruleSetInfo, RuleEngine engine, object factsHandleIn) { object factsHandleOut; if (factsHandleIn == null) { SqlConnection SQLConn = new SqlConnection(" Initial Catalog=Northwind; Data Source=(local); Integrated Security=SSPI;"); DataConnection RulesConn = new DataConnection("Northwind", "Customers", SQLConn); engine.Assert(RulesConn); factsHandleOut = RulesConn; } else factsHandleOut = factsHandleIn;
return factsHandleOut; } } }
|
Compile
the class library assembly, and deploy it to the Global Assembly Cache
(GAC). This can be done via a command prompt using the gacutil /if
command. After creating the custom fact retriever, define a vocabulary
and business rules. This example will schedule a service appointment
only if the customer's address is in the database.
Open
the Business Rule Composer, and create a new policy with one rule.
Define a vocabulary for accessing facts defined by an XML message. An
orchestration must provide the message when the policy executes. This
example gets the address a customer requested service at and decides
whether to approve the service request.
Right-click
the new vocabulary's version, and select Add New Definition. Select the
option to create a new database table or column definition in the
vocabulary, and click Next, as shown in Figure 1.
Give the definition an appropriate name, and leave the Binding Type set to Data Connection.
Within
the Database Information section of the window, click the Browse
button. After selecting a SQL Server instance with the Northwind
database, browse to the Customers table. Select the Address column of
the Customers table, as shown in Figure 2, and click OK.
Within
the Select Operation section of the window, select the Perform "Get"
Operation radio button. Set an appropriate display name for display in
the Business Rules Composer. When complete, the Database Table or
Database Table Column Definition window appears, as shown in Figure 3.
Click the Finish button to complete the vocabulary definition.
Select
the policy version in the Policy Explorer section of the Business Rule
Composer. The properties should appear in the lower-left region of the
Business Rule Composer.
Select the Fact Retriever property of the policy version, and click the ellipsis that appears.
In
the Select Configuration component, click the Browse button. In the
list of assemblies that appears, select the custom fact retriever
created previously in this example (shown in Figure 4).
NOTE
If you cannot locate the custom fact retriever assembly, verify that it is deployed to the GAC.
Select the class to complete configuring the custom fact retriever.
After creating the custom fact retriever to retrieve the DataConnection
and configuring the policy to use the custom fact retriever, it is time
to define the rules. So, define the business rule to compare the
requested service address with the customer addresses already in the
Northwind database. If there is a match, the service request will be
scheduled.
Deploy
the rules and invoke them from an orchestration, specifying the XML
messages that the policy expects. The rules engine will invoke the UpdateFactsDataConnection fact to the Northwind database to the rules engine facts. method of the custom fact retriever. The method will add a
3. How It Works
The rules engine
examines facts provided either directly from an orchestration or from a
custom fact retriever. The facts provided directly from an orchestration
are called short-term facts, and the orchestration supplies them each
time BizTalk invokes the rules engine. The facts provided from a custom
fact retriever are called long-term facts, and they can be reused each
time BizTalk invokes the rules engine.
A BizTalk orchestration can also treat the DataConnection in this example as a short-term fact. Accomplish this by creating a DataConnection
in an Expression shape and including it as a parameter to the Call
Rules shape. However, each orchestration instance would create its own DataConnection. You can improve the scalability and performance of the application by treating the DataConnection as a long-term fact and sharing it each time BizTalk invokes the rules engine.
In general, treating a fact as long-term is preferable under the following conditions:
The fact value can be shared each time BizTalk invokes the rules engine.
Retrieving the fact incurs a significant performance penalty.
Caching the fact value will still allow the rules to execute correctly.
The fact is not directly available in the orchestration that invokes the rules.
The rules engine invokes the custom fact retriever's UpdateFacts method each time the policy executes. This method decides when to update the facts. In this example, the UpdateFacts method examines the factsHandleIn parameter to check whether the DataConnection was already created. If the factsHandleIn parameter is null, the method creates the DataConnection, inserts it into the rules engine, and completes by returning the DataConnection object. The next time the rules engine invokes the method, the rules engine includes the object returned by the method in the factsHandleIn parameter. If the factsHandleIn parameter is not null, the method knows that it has already inserted the DataConnection into the rules engine, and it simply returns the same object.
Although this solution
example uses a simple algorithm to decide when the long-term fact needs
updating, the developer can implement a more sophisticated approach. For
example, the developer could refresh the facts every hour by returning a
DateTime object when the facts are refreshed and decide to update facts by comparing the last refresh time to the current time.